// n pcs from pole 1,  via pole 2, to pole 3 //<>//

int hnTotalStpes;
int hnDoneSteps;
int hnRemainSteps;
int hnDonePcntg;

cpoleFIFO poleIn = new cpoleFIFO();
cpoleFIFO poleOut = new cpoleFIFO();

void hanio(int npcs) {
  poleIn.clear();
  poleOut.clear();

  print("\n" + npcs + " plates moving. ");
  println(" Total " + ((int)pow(2, npcs) - 1) + " steps");

  hanio(numPlates, pole1, pole2, pole3);
}

void hanio(int pcs, cpole from, cpole via, cpole to) {
  if (pcs == 1) {
    poleOut.in(from);
    poleIn.in(to);
    println(from.poleNo, " --> ", to.poleNo);
  } else {
    hanio(pcs - 1, from, to, via);
    poleOut.in(from);
    poleIn.in(to);
    println(from.poleNo + 1, " --> ", to.poleNo + 1);
    hanio(pcs - 1, via, from, to);
  }
}

// ===== task fall to control hanio moving show ==== //
// non-blocking task show
int showTask = 0;

// moving target
int targetX = 0;
int targetY = 0;

// pole from, pole to
cpole fromPole, toPole;

// plate in moving currently
cplate movingPlate = null;

// move left or right, move stpes
boolean moveLeft;
int moveStpes;

void hanioShow() {
  if (speedCtrl.paused) {
    return;
  }

  moveStpes = speedCtrl.getMoveSteps();

  switch(showTask) {
  case 0:
    { // idle state, do nothing, just waiting
      break;
    }
  case 1:
    { // do it and get result in stack sk_HanoiPop and sk_HanoiPush
      preparePlates(numPlates);
      hanio(numPlates);
      showTask++;
      break;
    }
  case 2:
    { // get pole form/to, plate to move , figure out target X and Y to move to
      if (poleIn.isNotEmpty()) { // poleIn & poleOut are same len
        hnDoneSteps++;
        hnRemainSteps--;
        hnDonePcntg = (int)((((float)hnDoneSteps)/hnTotalStpes)*100);

        fromPole = poleOut.out();
        toPole = poleIn.out();
        movingPlate = fromPole.plateStack.pop();

        targetY = 267;
        targetX = toPole.x;

        if (movingPlate.x > targetX) {
          moveLeft = true;
        } else {
          moveLeft = false;
        }

        showTask = 3;
      } else {
        endShowTask();
      }
      break;
    }
  case 3:
    { // lift up
      if (movingPlate.y - targetY > moveStpes) {
        movingPlate.y -= moveStpes;
      } else {
        movingPlate.y = targetY;

        // targetY for dropping later
        targetY = PLATE_YPOS[toPole.plateStack.size()];
        showTask = 4;
      }
      break;
    }
  case 4:
    { // move horizontal (L or R)
      if (moveLeft) {
        if (movingPlate.x - targetX > moveStpes) {
          movingPlate.x -= moveStpes;
        } else {
          movingPlate.x = targetX;
          showTask = 5;
        }
      } else {
        if (targetX - movingPlate.x > moveStpes) {
          movingPlate.x += moveStpes;
        } else {
          movingPlate.x = targetX;
          showTask = 5;
        }
      }
      break;
    }
  case 5:
    { // drop down
      if (targetY - movingPlate.y > moveStpes) {
        movingPlate.y += moveStpes;
      } else {
        movingPlate.y = targetY;
        showTask = 6;
      }
      break;
    }
  case 6:
    { // push plate in to target pole
      playSound(sndDrop);
      toPole.plateStack.push(movingPlate);
      movingPlate = null;
      showTask = 2; // repeat
      break;
    }
  default:
    {
      endShowTask();
    }
  }
}

void endShowTask() {
  showTask = 0;
  println("all tasks done");

  for (cAllButton i : clickBtns) {
    i.enabled = true; // up, down, go, pause, stop enable
  }
  // but
  btnPause.invisible(); // pause invisible (and will be disable of course)
  btnStop.invisible(); // stop invisible (and will be disable of course)

  // play done sound
  playSound(sndDone);

  // no plate is in moving
  movingPlate = null;
}

void showProgress() {
  textSize(30);
  fill(#A6CFF2);
  text(hnTotalStpes, 47, 110);
  String str = hnDoneSteps + " , - " + hnRemainSteps;
  text(str, 47, 140);
  text(hnDonePcntg + "%", 47, 180);
}

void drawProgressBar() {
  rectMode(CORNER);
  colorMode(HSB, 360, 100, 100);

  int hue = (int)map(hnDonePcntg, 0, 100, 0, 150);
  int xpos = (int)map(hnDonePcntg, 0, 100, 0, width);

  fill(hue, 100, 100); // HSB: H 360, S 100 B 100 range
  rect(0, 894, xpos, 894, 3, 3, 3, 3);

  colorMode(RGB); // looks like no need this
  rectMode(RADIUS);
}
